import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Player here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Player extends Actor
{
    private Whip whip;
    private CollisionBox colDown;
    private CollisionBox colPlayer;
    private CollisionBox colRight;
    private CollisionBox colLeft;
    private GameWorld world;
    
    private int runIndex;
    private int rollIndex;
    private int whipIndex;
    private int restIndex;
    private int dizzyIndex;
    private int dizzyRepeat;
    private int animationDelay;
    private int dir;
    private int action;
    private int lastAction;
    private int yVel;
    private Timer timer=new Timer();
    private Timer rollTimer=new Timer();
    private Timer whipTimer=new Timer();
    private Timer scoreTimer=new Timer();
    private GreenfootImage[][][] skins;
    private boolean isJumping;
    private boolean isRolling;
    private boolean isDizzy;
    private boolean isGettingUp;
    private boolean isFlying;
    private boolean playingAnimation;
    private boolean manMode=false;
    
    private int health;
    private boolean invulnerable;
    private int lives;
    private int score;
    
    private static final int RIGHT=0;
    private static final int LEFT=1;
    private static final int UP=2;
    private static final int DOWN=3;
        
    public Player()
    {
        health=100;
        lives=5;
        invulnerable=false;
        
        whipTimer.setTime(9001);
        
        runIndex=0;
        rollIndex=0;
        whipIndex=0;
        restIndex=0;
        dizzyIndex=0;
        dizzyRepeat=0;
        animationDelay=15;
        dir=RIGHT;
        
        isJumping=false;
        isRolling=false;
        isDizzy=false;
        isGettingUp=false;
        isFlying=false;
        playingAnimation=false;
        
        action=0;
        lastAction=0;
        yVel=-1;
        skins=new GreenfootImage[11][11][2];
        createImageList();
    }
    
    public void act() 
    {   
        timer.tick();
        rollTimer.tick();
        whipTimer.tick();
        scoreTimer.tick();
        
        world=(GameWorld)getWorld();
        
        debug();
        
        if(world.isWorldAnimationPlaying())
        return;
             
        whip=world.getWhip();
        colDown=world.getColDown();
        colPlayer=world.getColPlayer();
        colRight=world.getColRight();
        colLeft=world.getColLeft();
        
           
        if(isTouchingGround())
        {
            if(action!=7)
            yVel= -1;
            
            setLocation(getX(),getWorld().getHeight()-145);
            
            isJumping=false;
            
            if(!isAnyKeyDown() && action<5)
            action=0;
            
            if((Greenfoot.isKeyDown("right") || Greenfoot.isKeyDown("left")) && action<5 && canMove())
            action=1;
            
            if(Greenfoot.isKeyDown("down") && action<5)
            action=3;
            
            if(Greenfoot.isKeyDown("s") && action<5 && isDizzy==false)
            action=4;
            
            if(Greenfoot.isKeyDown("up") && action<5)
            yVel=-14;
            
            if(Greenfoot.isKeyDown("a") && action<6 && whipTimer.getTime()>1000)
            action=5;
        }else
        {
            if(Greenfoot.isKeyDown("a") && action<7 && whipTimer.getTime()>1000)
            action=6;
            else
        
            if(action<4)
            action=2;
        }
        
        if(getY()>world.getHeight())
        action=8;
        
        if(action==2 && isWallAbove()==true)
        yVel=1;
        
        if(action!=lastAction)
        aftermath();
        else
        
        switch(action)
        {
            case 0:     stand();
                        break;
            case 1:     run();
                        break;
            case 2:     jump();
                        break;
            case 3:     crouch();
                        break;
            case 4:     roll();
                        break;
            case 5:     whip();
                        break;
            case 6:     whipJump();
                        break;
            case 7:     fall();
                        break;
            case 8:     die();
                        break;
            default:    break;   
        }
       
        
        yVel=yVel+1;
        
        
        setLocation(getX(),getY()+yVel);   
        
        if(getY()>world.getHeight()+100)
        {
            //setLocation(getX(),100);
            action=8;
        }
        
        colPlayer.updateHitbox(action,dir);
        colRight.updateForAction(action,RIGHT);
        colLeft.updateForAction(action,LEFT); 
                         
    }
    
    public void createImageList()
    {
        skins[0][0][0]=new GreenfootImage("standing0.png");
        skins[0][0][1]=new GreenfootImage("standing0.png");
        skins[0][0][1].mirrorHorizontally();
        
        for(int i=0;i<=8;i++)
        {
            skins[1][i][0]=new GreenfootImage("running"+i+".png");
            skins[1][i][1]=new GreenfootImage("running"+i+".png");
            skins[1][i][1].mirrorHorizontally();
        }
        
        skins[2][0][0]=new GreenfootImage("jumping0.png");
        skins[2][0][1]=new GreenfootImage("jumping0.png");
        skins[2][0][1].mirrorHorizontally();
        
        skins[2][1][0]=new GreenfootImage("jumping1.png");
        skins[2][1][1]=new GreenfootImage("jumping1.png");
        skins[2][1][1].mirrorHorizontally();
        
        skins[3][0][0]=new GreenfootImage("crouching0.png");
        skins[3][0][1]=new GreenfootImage("crouching0.png");
        skins[3][0][1].mirrorHorizontally();
        
        for(int i=0;i<=6;i++)
        {
            skins[4][i][0]=new GreenfootImage("rolling"+i+".png");
            skins[4][i][1]=new GreenfootImage("rolling"+i+".png");
            skins[4][i][1].mirrorHorizontally();
        }
        
        for(int i=0;i<=4;i++)
        {
            skins[5][i][0]=new GreenfootImage("whip"+i+".png");
            skins[5][i][1]=new GreenfootImage("whip"+i+".png");
            skins[5][i][1].mirrorHorizontally();
        }
        
        for(int i=0;i<=3;i++)
        {
            skins[6][i][0]=new GreenfootImage("whipJump"+i+".png");
            skins[6][i][1]=new GreenfootImage("whipJump"+i+".png");
            skins[6][i][1].mirrorHorizontally();
        }
        
        skins[7][0][0]=new GreenfootImage("falling0.png");
        skins[7][0][1]=new GreenfootImage("falling0.png");
        skins[7][0][1].mirrorHorizontally();
        
        skins[8][0][0]=new GreenfootImage("dead0.png");
        skins[8][0][1]=new GreenfootImage("dead0.png");
        skins[8][0][1].mirrorHorizontally();
        
        for(int i=0;i<=2;i++)
        {
            skins[9][i][0]=new GreenfootImage("dizzy"+i+".png");
            skins[9][i][1]=new GreenfootImage("dizzy"+i+".png");
            skins[9][i][1].mirrorHorizontally();
        }
        
        for(int i=0;i<=10;i++)
        skins[10][i][0]=new GreenfootImage("resting"+i+".png");
        
    }
    
    public void stand()
    {
        action=0;
        
        if(lastAction!=action)
        return;
        
        setSkin(skins[0][0][dir]);
    }
    
    public void run()
    {
        action=1;
        
        if(lastAction!=action)
        return;
        
        if(Greenfoot.isKeyDown("right"))
        {
            dir=RIGHT;
        }
        else
        if(Greenfoot.isKeyDown("left"))
        {
            dir=LEFT;
        }
        
        
        if(timer.wait(animationDelay))
        return;
                
        scroll(17);
        
        if(runIndex>8)
        runIndex=0; 
                      
        setSkin(skins[1][runIndex][dir]);
        runIndex++;
    }
    
    public void jump()
    {
        action=2;
        if(lastAction!=action)
        return;
                  
        if(Greenfoot.isKeyDown("right"))
        {
            dir=RIGHT;
            scroll(10);
        }
        else
        if(Greenfoot.isKeyDown("left"))
        {
            dir=LEFT;
            scroll(10);
        }
        
        
        if(isJumping==false)
        {
            setSkin(skins[2][0][dir]); 
                if(timer.wait(200))
                return;
            isJumping=true;
        }else
            setSkin(skins[2][1][dir]);

    }
    
    public void crouch()
    {
        action=3;
        
        if(lastAction!=action)
        return;
        
        if(Greenfoot.isKeyDown("right"))
        dir=RIGHT;
        else
        if(Greenfoot.isKeyDown("left"))
        dir=LEFT;
        
        setSkin(skins[3][0][dir]);
    }
    
    public void roll()
    {
        action=4;
        rollTimer.count();
        
        if(lastAction!=action)
        return;
            
        if(timer.wait(40) && isRolling==false)
        return;
        
        if(timer.wait(animationDelay) && isRolling==true)
        return;
        
        
        if(isRolling==false && rollIndex<2)
        {
            setSkin(skins[4][rollIndex][dir]);
            rollIndex++;
            scroll(25);
            return;
        }
        
        isRolling=true;
        setSkin(skins[4][rollIndex][dir]);
        scroll(17);
        
        rollIndex++;
        if(rollIndex>5)
        rollIndex=2;
    }
    
    public void whip()
    {
        action=5;
        
        if(lastAction!=action)
        return;
        
        whipTimer.reset();
        
        if(timer.wait(40))
        return;
        
        if(whipIndex>4)
        {
            action=0;
            
            /*if(whip.isTouchingLedge())
            {
                setSkin(skins[6][3][dir]);
                yVel=-20;
                scroll(100);
                isFlying=true;
            }*/
            
            GreenfootSound sound=new GreenfootSound("whip_crack.mp3");
            sound.play();
            return;
        }
                      
        setSkin(skins[5][whipIndex][dir]);
        whip.setSkin(whipIndex,dir);
        whipIndex++;    
    }
    
    public void whipJump()
    {
        action=6;
        
        if(lastAction!=action)
        return; 
        
        whipTimer.reset();
        
        if(whipIndex<=2)
        {
            setSkin(skins[6][whipIndex][dir]);
            whip.setSkin(whipIndex+5,dir);
        }else
            whip.attach(7,dir);
        
        
        if(Greenfoot.isKeyDown("right"))
        {
            dir=RIGHT;
            scroll(10);
        }
        else
        if(Greenfoot.isKeyDown("left"))
        {
            dir=LEFT;
            scroll(10);
        }
        
        if(timer.wait(40))
        return;
        
        if(whipIndex>2)
        {
            action=2;
            
            if(whip.isTouchingLedge())
            {
                setSkin(skins[6][3][dir]);
                yVel=-17;
                scroll(100);
                isFlying=true;
            }
            
            GreenfootSound sound=new GreenfootSound("whip_hit.mp3");
            sound.play();
            return;
        }
        
        whipIndex++;
    }
    
    public int getHealth()
    {
        return(health);
    }
    
    public void getHurt(int damage)
    {
        if(invulnerable==true)
        return;
        
        action=7;
        
        if(invulnerable==false)
        {   
            invulnerable=true;
            
            if(health>damage)
            health-=damage;
            else
            if(health>10)
            health=10;
            else
            health=0;
            
            world.getHealthBar().updateImage(health);
            yVel=-10;
            setLocation(getX(),getY()+yVel);  
        } 
    }
    
    public void fall()
    {
        setImage(skins[7][0][dir]);
        scroll(-10);
        whip.hide();
        
        if(isTouchingGround())
        {   
            invulnerable=false;
            //yVel=-5;
            
            if(health>0)
            action=0;
            else
            {
                action=8;
                invulnerable=true;
            }
        }
    }
    
    public void die()
    {
        action=8;
        invulnerable=true;
        
        setSkin(skins[8][0][dir]);
        whip.hide();
        
        if(world.playedAnimation()==false)
        {
            lives--;
            health=0;
            world.getHealthBar().updateImage(health);
            world.getLives().updateImage(lives);
            
            world.playAnimation(1);
            playingAnimation=true;
            
            if(lives==0)
            world.playAnimation(2);
            
            world.removeSnakes();
            
            return;
        }
         
        health=100;
        world.getHealthBar().updateImage(health);
        
        setSkin(skins[9][dizzyIndex][dir]);
        
        if(dizzyRepeat<5)
        {
            if(timer.wait(100))
            return;
                            
            dizzyIndex++;
            dizzyRepeat++;
            if(dizzyIndex>1)
            dizzyIndex=0;
                                
            return;
        }
                            
        setSkin(skins[9][2][dir]);
                            
        if(timer.wait(120))
        return;
        
        rollTimer.reset();
        isDizzy=false;
                            
        resetIndex();
        
        action=0;
        invulnerable=false;
        isGettingUp=false;
        playingAnimation=false;
        world.resetAnimation();
    }  
        
    public void aftermath()
    {
        if(!(action<8))
        {
            lastAction=action;
            rollTimer.reset();
            resetIndex();
            return;
        }
        
        
        switch(lastAction)
        {              
            case 4:     if(rollTimer.getTime()<1000)
                        {
                            setSkin(skins[4][6][dir]);
                            
                            if(timer.wait(60))
                            return;
                            
                            scroll(17);
                            lastAction=action;
                            resetIndex();
                        }else
                        
                        {          
                            isDizzy=true;
                            
                            setSkin(skins[9][dizzyIndex][dir]);
                            
                            if(dizzyRepeat<3)
                            {
                                if(timer.wait(100))
                                return;
                            
                                dizzyIndex++;
                                dizzyRepeat++;
                                if(dizzyIndex>1)
                                dizzyIndex=0;
                                
                                return;
                            }
                            
                            setSkin(skins[9][2][dir]);
                            
                            if(timer.wait(120))
                            return;
                            
                            lastAction=action;
                            resetIndex();
                        }
                            
                        rollTimer.reset();
                        isDizzy=false;
                        break;  
                        
            case 5: case 6:     whip.hide();
                                
                                if(isFlying==true)
                                {
                                    if((Greenfoot.isKeyDown("right") && dir==RIGHT) || (Greenfoot.isKeyDown("left") && dir==LEFT))
                                    scroll(10);
                                    
                                    if(timer.wait(200))
                                    return;
                                    
                                    whipTimer.reset();
                                    //whipTimer.setCount(9001);
                                    whipTimer.setTime(950);
                                         
                                }else
                                     whipTimer.count();
                                    
                                isFlying=false;
                                lastAction=action;
                                resetIndex();
                                break;
                        
            default:    lastAction=action;
                        timer.reset();
                        resetIndex();
                        break;
        }
    }
    
    
    public void resetIndex()
    {
        if(action!=4)
        {
            rollIndex=0;
            dizzyIndex=0;
            dizzyRepeat=0;
            isRolling=false;
        }
        
        if(action!=1)
        runIndex=0;
        
        if(action!=5)
        whipIndex=0;
    }
                    
    
    public void scroll(int num)
    {
        if(!canMove())
        return;
        
        switch(dir)
        {
            case RIGHT: world.changeScrollx(num*-1);
                        break;
            case LEFT:  world.changeScrollx(num);
                        break;
            default:    break;
        }
    }
    
    public void setSkin(GreenfootImage skin)
    {      
        setImage(skin);
    }
    
    public boolean isTouchingGround()
    { 
        if(colDown.isTouchingGround() && yVel>-1)
        return(true);
        else
        return(false);
    }
    
    public boolean canMove()
    {
        /*int distance=getImage().getWidth()/2+10;
        
        if(Greenfoot.isKeyDown("right"))//dir==RIGHT)
            if(getOneObjectAtOffset(50,0,Ground.class)==null &&
            (getOneObjectAtOffset(distance,0,Wall.class)==null && action!=5) ||
            (getOneObjectAtOffset(distance,25,Wall.class)==null && action==5))
            return(true);
            else
            return(false);
        else
        if(Greenfoot.isKeyDown("left"))
            if(getOneObjectAtOffset(-50,0,Ground.class)==null &&
            (getOneObjectAtOffset(-distance,0,Wall.class)==null && action!=5) ||
            (getOneObjectAtOffset(-distance,25,Wall.class)==null && action==5))
            return(true);
            else
            return(false);
            
            return(true);*/
            
        if(Greenfoot.isKeyDown("right"))
        {
            if(!colRight.isTouchingGround() && !colRight.isTouchingWall())
            return(true);
            else
            return(false);
        }
        else
        if(Greenfoot.isKeyDown("left"))
        {
            if(!colLeft.isTouchingGround() && !colLeft.isTouchingWall())
            return(true);
            else
            return(false);
        }else
        if(dir==RIGHT)
        {
            if(!colRight.isTouchingGround() && !colRight.isTouchingWall())
            return(true);
            else
            return(false);
        }
        else
        if(dir==LEFT)
        {
            if(!colLeft.isTouchingGround() && !colLeft.isTouchingWall())
            return(true);
            else
            return(false);
        }
        
        return(true);
    }
        
    public boolean isInvulnerable()
    {
        return(invulnerable);
    }
    
    public void setInvulnerable(boolean state)
    {
        invulnerable=state;
    }
    
    public boolean isWallAbove()
    {
        if(getOneObjectAtOffset(0,-getImage().getHeight()/2-5,Wall.class)!=null)
        return(true);
        else
        return(false);
    }
    
    public void setPlayingAnimation(boolean state)
    {
        playingAnimation=state;
    }

   /* private boolean isIntersecting(java.lang.Class cls)
    {
        Actor actor=getOneIntersectingObject(cls);
        
        if(actor==null)
        return(false);
        
        return(isVisuallyIntersecting(actor));
        
        java.util.List actors=getIntersectingObjects(Ground.class);
        
        if(actors.isEmpty())
        return(false);
        
        if(isVisuallyIntersecting((Actor)actors.get(0)))
        return(true);
        else
            if(actors.size()>1)
            return(isVisuallyIntersecting((Actor)actors.get(1)));
            
       return(false);
    }
    
    private boolean isVisuallyIntersecting(Actor actor)    
    {    
        // get width and height of images    
        int wA = getImage().getWidth();    
        int hA = getImage().getHeight();    
        int wB = actor.getImage().getWidth();    
        int hB = actor.getImage().getHeight();    
        // get world coordinates of origin point (0, 0) of images    
        int xAw = getX()-wA/2;    
        int yAw = getY()-hA/2;    
        int xBw = actor.getX()-wB/2;    
        int yBw = actor.getY()-hB/2;    
        // determine (x, y) on each image to begin checking from    
        // and dimensions of area to check    
        int xA = 0, yA = 0, xB = 0, yB = 0; // initialize start coord fields    
        int w = 0, h = 0; // initialize scan dimension fields    
        // determine values for fields just initialized    
        if (xAw > xBw)    
        {    
            xB = xAw-xBw;    
            if (xAw+wA > xBw+wB) w = wB-xB; else w = wA;    
        }    
        else    
        {    
            xA = xBw-xAw;    
            if (xBw+wB > xAw+wA) w = wA-xA; else w = wB;    
        }    
        if (yAw > yBw)    
        {    
            yB = yAw-yBw;    
            if (yAw+hA > yBw+hB) h = hB-yB; else h = hA;    
        }    
        else    
        {    
            yA = yBw-yAw;    
            if (yBw+hB > yAw+hA) h = hA-yA; else h = hB;    
        }    
        // perform checking    
        java.awt.Color trans = new java.awt.Color(0, 0, 0, 0);    
        for (int x=0; x<w; x++) for (int y=0; y<h; y++)    
            {    
                if (!trans.equals(getImage().getColorAt(xA+x, yA+y)) &&    
                    !trans.equals(actor.getImage().getColorAt(xB+x, yB+y)))   
                    return true;  
        }    
        return false;    
    } 
    

    
    public boolean isAnyKeyDown()
    {
        String keys = "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_-+={[}]|\\<,>.?/`~";  
        String[] specialKeys = { "enter", "escape", "space", "backspace", "tab", "shift", "control",  "up", "down", "left", "right", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" };  
        
        int i = 0;  
        
        for (i=0; i<keys.length(); i++)
            if (Greenfoot.isKeyDown(keys.substring(i, i+1)))
            break;  
        
        boolean keyFoundDown =  i < keys.length();  
            
        if (!keyFoundDown)  
        {  
            for (i=0; i<specialKeys.length; i++)
                if (Greenfoot.isKeyDown(specialKeys[i]))
                break;  
                
            keyFoundDown = i < specialKeys.length;  
        }  
            
        return(keyFoundDown);
    } */
    
    public boolean isAnyKeyDown()
    {
        String[] keys={"right","left","up","down","a","s"};
        
        int i=0;
        
        for(i=0;i<keys.length;i++)
            if(Greenfoot.isKeyDown(keys[i]))
            break;
            
        return(i<keys.length);
    }
    
    public void rest()
    {
        int index=0;
         
        if(timer.wait(100))
        return;
        
                
        restIndex++;
        
        switch(restIndex)
        {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
            case 10:    index=restIndex;
                        break;
            case 11:    index=4;
                        break;
            case 12:    index=3;
                        break;
            default:    index=2;
                        break;
        }
        
        setSkin(skins[10][index][0]);
                      
        
    }
    
    public boolean isDoneResting()
    {
        if(restIndex>14)
        return(true);
        else
        return(false);
    }
        
    
    public void reset()
    {
        health=100;
        lives=5;
        invulnerable=false;
        
        whipTimer.setTime(9001);
        
        runIndex=0;
        rollIndex=0;
        whipIndex=0;
        restIndex=0;
        dizzyIndex=0;
        dizzyRepeat=0;
        animationDelay=15;
        dir=RIGHT;
        
        isJumping=false;
        isRolling=false;
        isDizzy=false;
        isGettingUp=false;
        isFlying=false;
        playingAnimation=false;
        
        action=0;
        lastAction=0;
        yVel=-1;

    }
    
    public void debug()
    {
        world.removeObjects(world.getObjects(Display.class));
        if(world.isDebugOn())
        {
            world.addObject(new Display(health+""),450,100);
            world.addObject(new Display("Health",20),450,70);/*
            world.addObject(new Display(action+""),100,100);
            world.addObject(new Display("Action",20),110,70);
            world.addObject(new Display(lastAction+""),170,100);
            world.addObject(new Display("Last Action",20),190,70);
            world.addObject(new Display(whipTimer.getCount()+"",20),200,120);
            world.addObject(new Display("A: Latigo  S: Rodar",20),400,70);
            world.addObject(new Display("yVel",20),680,140);
            world.addObject(new Display(yVel+"",20),680,170);*/
        
            world.addObject(new Display(action+""),300,100);
            world.addObject(new Display("Action",20),310,70);
            
        
            world.addObject(new Display("scroll",20),680,70);
            world.addObject(new Display(world.getScrollx()*-1+"",20),680,100);
            
            world.addObject(new Display("Invulnerable",20),680,150);
            
            if(invulnerable==true)
            world.addObject(new Display("True",20),680,170);
            else
            world.addObject(new Display("False",20),680,175);
        }
        
    }
    
    public void calculateScore()
    {
        int newScore=(scoreTimer.getTime()/1000)*-1;
        
        if (UserInfo.isStorageAvailable()) 
        {
            UserInfo myInfo = UserInfo.getMyInfo();
            if (newScore > myInfo.getScore() || myInfo.getScore()==0) 
            {
                myInfo.setScore(newScore);
                myInfo.store();  // write back to server
            }
        }
             
    }
}
